;; The first four lines of this file were added by Dracula.
;; They tell DrScheme that this is a Dracula Modular ACL2 program.
;; Leave these lines unchanged so that DrScheme can properly load this file.
#reader(planet "reader.rkt" ("cce" "dracula.plt") "modular" "lang")
(require "IFileReader.lisp")

(module MFileReader
  (include-book "list-utilities" :dir :teachpacks)
  (include-book "io-utilities" :dir :teachpacks)
  
  ;converts a rational number to a list of chars
  (defun RatToChars (rational decimals)
    (str->chrs (rat->str rational decimals)))
  
  ;converts a list of chars to a rational numbers
  (defun CharsToRat (chars)
    (str->rat (chrs->str chars)))
  
  ;extracts a the characters between two commas in a list of chars
  (defun ExtractBetweenCommas (lineAsChars startComma endComma commaCount)
    (let* ((nextChar (car lineAsChars))(restOfLine (cdr lineAsChars)))
      (if (equal nextChar #\,)
          (ExtractBetweenCommas restOfLine startComma endComma (+ commaCount 1))
          (if (and (>= commaCount startComma) (< commaCount endComma))
              (if (equal nextChar nil)
                  nil
                  (cons nextChar (ExtractBetweenCommas restOfLine startComma endComma commaCount)))
              (if (< commaCount startComma)
                  (ExtractBetweenCommas restOfLine startComma endComma commaCount)
                  nil)))))
  
  ;extracts everything after a certain comma in a list of chars
  (defun ExtractFromComma (lineAsChars startComma commaCount)
    (let* ((nextChar (car lineAsChars))(restOfLine (cdr lineAsChars)))
      (if (equal nextChar #\,)
          (if (>= (+ 1 commaCount) startComma)
              restOfLine
              (ExtractFromComma restOfLine startComma (+ commaCount 1)))
          (if (equal nextChar nil)
              nil
              (ExtractFromComma restOfLine startComma commaCount)))))
  
  
  
  (defun breakAtNextLineHelper(chars prefix)
    (let* ((firstNextChar (car chars))(secondNextChar (cadr chars)))
      (if (or (equal firstNextChar #\newline) (equal firstNextChar #\return) (equal firstNextChar nil))
          (if (or (equal secondNextChar #\newline) (equal secondNextChar #\return))
              (list prefix (cddr chars))
              (list prefix (cdr chars)))
          (breakAtNextLineHelper (cdr chars) (append prefix (list firstNextChar))))))
  
  ;returns a two element pair of the current line and the rest of the file
  (defun breakAtNextLine (fileAsChars)
    (breakAtNextLineHelper fileAsChars nil))
  
  
  ; trim left space
  (defun trimLeftSpace (list)
    (if (equal #\Space (car list))
        (trimLeftSpace (cdr list))
        list))
  
  ; splits on space, return list of charlists
  (defun splitOnSpace (list)
    (if (null list)
        nil
        (let* ((split (break-at #\Space list))
               (head (car split))
               (tail  (trimLeftSpace (cadr split))))
          (cons head (splitOnSpace tail)))))
  
  ; goes through a list and tries to turn every element into an int
  ; otherwise it is changed to a string
  (defun coerceEach (list)
    (if (null list)
        nil
        (let* ((str (chrs->str (car list)))
               (int (str->rat str)))
          (if (and (equal int 0) (not (equal (caar list) #\0)))
              (cons str (coerceEach (cdr list)))
              (cons int (coerceEach (cdr list)))))))
  
  
  ; takes a string, and turns it into a list of either strings or ints, split at whitespace 
  (defun stringToArgs (string)
    (coerceEach (splitOnSpace (trimLeftSpace (str->chrs string)))))
  
  (export IFileReader))